#!/usr/bin/env python3
# Copyright (c) 2021 maminjie <canpool@163.com>
# SPDX-License-Identifier: MulanPSL-2.0

"""
This script is based on gitee REST API, to manage repositories on the gitee.com

Reference https://gitee.com/api/v5/swagger
"""

import sys
import os
import json
import urllib
import urllib.request
import urllib.parse
import urllib.error


class Gitee(object):
    """
    Gitee is a helper class to abstract gitee.com api
    """
    def __init__(self, token):
        self.params = {
            "access_token":token
            }
        self.headers = {
            'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW 64; rv:50.0) Gecko/20100101 Firefox/50.0'
            }

    def http_request(self, url, data=None, headers={}, method=None):
        req = urllib.request.Request(url=url, data=data, headers=headers, method=method)
        try:
            result = urllib.request.urlopen(req)
            return result.read().decode("utf-8")
        except urllib.error.HTTPError as e:
            print("{} ERROR: ".format(method) + str(url).split("?")[0])
            print("{} ERROR: ".format(method) + str(e.code) + " " + e.reason)
            return None
        except urllib.error.URLError as e:
            print("{} ERROR: ".format(method) + str(url).split("?")[0])
            print("{} ERROR: ".format(method) + e.reason)
            return None

    def put_request(self, url, values, headers=None):
        if headers is None:
            headers = self.headers.copy()
        data = urllib.parse.urlencode(values).encode('utf-8')
        return self.http_request(url=url, data=data, headers=headers, method="PUT")

    def post_request(self, url, values, headers=None):
        if headers is None:
            headers = self.headers.copy()
        data = urllib.parse.urlencode(values).encode('utf-8')
        return self.http_request(url=url, data=data, headers=headers, method="POST")

    def patch_request(self, url, values, headers=None):
        if headers is None:
            headers = self.headers.copy()
        data = urllib.parse.urlencode(values).encode('utf-8')
        return self.http_request(url=url, data=data, headers=headers, method="POST")

    def delete_request(self, url, headers=None):
        if headers is None:
            headers = self.headers.copy()
        return self.http_request(url=url, headers=headers, method="DELETE")

    def get_request(self, url, headers=None):
        if headers is None:
            headers = self.headers.copy()
        return self.http_request(url=url, headers=headers, method="GET")

    def put(self, url, values):
        values["access_token"] = self.params["access_token"]
        return self.put_request(url, values)

    def post(self, url, values):
        values["access_token"] = self.params["access_token"]
        return self.post_request(url, values)

    def patch(self, url, values):
        values["access_token"] = self.params["access_token"]
        return self.patch_request(url, values)

    def delete(self, url, param=""):
        url = self.__join_url(url, param)
        return self.delete_request(url)

    def get_json(self, url):
        headers = self.headers.copy()
        headers["Content-Type"] = "application/json;charset=UTF-8"
        resp = self.get_request(url, headers)
        if resp is None:
            return None
        if resp:
            return json.loads(resp)
        return resp

    def __join_url(self, url, param):
        separator = "?"
        if param:
            separator = "&"
        url += param + separator + "access_token={}".format(self.params["access_token"])
        return url

    def get(self, url, param=""):
        url = self.__join_url(url, param)
        return self.get_json(url)

    def get_branches(self, owner, repo):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/branches"
        url = url_template.format(owner=owner, repo=repo)
        return self.get(url)

    def get_one_branch(self, owner, repo, branch):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/branches/{branch}"
        url = url_template.format(owner=owner, repo=repo, branch=branch)
        return self.get(url)

    def create_branch(self, owner, repo, refs, branch_name):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/branches"
        url = url_template.format(owner=owner, repo=repo)
        values = {}
        values["refs"] = refs
        values["branch_name"] = branch_name
        return self.post(url, values)

    def set_branch_protection(self, owner, repo, branch):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/branches/{branch}/protection"
        url = url_template.format(owner=owner, repo=repo, branch=branch)
        values = {}
        return self.put(url, values)

    def delete_branch_protection(self, owner, repo, branch):
        """ Note: Operation is not allowed """
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/branches/{branch}/protection"
        url = url_template.format(owner=owner, repo=repo, branch=branch)
        return self.delete(url)

    def get_commits(self, owner, repo, sha="", author="", since="", until="", page=1, per_page=20):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/commits"
        url = url_template.format(owner=owner, repo=repo)
        param = "?page={}&per_page={}".format(page, per_page)
        if sha:
            param += "&sha={}".format(sha)
        if author:
            param += "&author={}".format(author)
        if since:
            param += "&since={}".format(since)
        if until:
            param += "&until={}".format(until)
        return self.get(url, param)

    def get_one_commit(self, owner, repo, sha):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/commits/{sha}"
        url = url_template.format(owner=owner, repo=repo, sha=sha)
        return self.get(url)

    def get_contents(self, owner, repo, path, ref="master"):
        """Gets the content under the specific path of the owner/repo"""
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/contents/{path}"
        url = url_template.format(owner=owner, repo=repo, path=path)
        param = "?ref={}".format(ref)
        return self.get(url, param)

    def get_org_repos(self, org, repo_type, page=1, per_page=20):
        """
        Get repos of org

        Parameters:
          repo_type - all, public, private
        """
        url_template = "https://gitee.com/api/v5/orgs/{org}/repos"
        url = url_template.format(org=org)
        param = "?type={}&page={}&per_page={}".format(repo_type, page, per_page)
        return self.get(url, param)

    def get_user_repos(self, repo_type, page=1, per_page=20):
        """
        Get repos of user

        Parameters:
          repo_type - all, owner, personal, member, public, private
        """
        url_template = "https://gitee.com/api/v5/user/repos"
        url = url_template
        param = "?type={}&sort=full_name&page={}&per_page={}".format(repo_type, page, per_page)
        return self.get(url, param)

    def get_one_repo(self, owner, repo):
        """get user one repo info"""
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}"
        url = url_template.format(owner=owner, repo=repo)
        return self.get(url)

    def __create_repo(self, url, name, description, license, private):
        if license != "":
            lic_list = self.get_licenses()
            if license not in lic_list:
                print("license name \"{}\" is not support".format(license))
                return None
        values = {}
        values["name"] = name
        values["description"] = description
        values["has_issues"] = "true"
        values["has_wiki"] = "true"
        values["can_comment"] = "true"
        if license:
            values["license_template"] = license
        if private == False:
            values["private"] = "false"
        else:
            values["private"] = "true"
        return self.post(url, values)

    def create_repo(self, name, description, license="", private=False):
        url = "https://gitee.com/api/v5/user/repos"
        return self.__create_repo(url, name, description, license, private)

    def create_org_repo(self, name, description, org, license="", private=False):
        url = "https://gitee.com/api/v5/orgs/{org}/repos".format(org=org)
        return self.__create_repo(url, name, description, license, private)

    def delete_repo(self, owner, repo):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}"
        url = url_template.format(owner=owner, repo=repo)
        return self.delete(url)

    def get_contributors(self, owner, repo):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/contributors"
        url = url_template.format(owner=owner, repo=repo)
        return self.get(url)

    def get_tags(self, owner, repo):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/tags"
        url = url_template.format(owner=pwner, repo=repo)
        return self.get(url)

    def create_tag(self, owner, repo, tag_name, refs="master"):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/tags"
        url = url_template.format(owner=owner, repo=repo)
        values = {}
        values["refs"] = refs
        values["tag_name"] = tag_name
        return self.post(url, values)

    def get_reviewers(self, owner, repo):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{pkg}/collaborators"
        url = url_template.format(owner=owner, pkg=repo)
        return self.get(url)

    def get_collaborators(self, owner, repo):
        return self.get_reviewers(owner, repo)

    def is_collaborator(self, owner, repo, username):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/collaborators/{username}"
        url = url_template.format(owner=owner, repo=repo, username=username)
        if self.get(url) is None:
            return False
        return True

    def add_collaborator(self, owner, repo, username, permission="push"):
        """
        permission - admin, push, pull
            (admin:manager, push:developer, pull:observer)
        """
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/collaborators/{username}"
        url = url_template.format(owner=owner, repo=repo, username=username)
        values = {}
        values["permission"] = permission
        return self.put(url, values)

    def delete_collaborator(self, owner, repo):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/collaborators/{username}"
        url = url_template.format(owner=owner, repo=repo, username=username)
        return self.delete(url)

    def get_collaborator_permission(self, owner, repo, username):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/collaborators/{username}/permission"
        url = url_template.format(owner=owner, repo=repo, username=username)
        return self.get(url)

    def get_forks(self, owner, repo, page=1, per_page=20):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/forks"
        url = url_template.format(owner=owner, repo=repo)
        param = "?sort=newest&page={}&per_page={}".format(page, per_page)
        return self.get(url, param)

    def fork_repo(self, owner, repo):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/forks"
        url = url_template.format(owner=owner, repo=repo)
        values = {}
        return self.post(url, values)

    def get_releases(self, owner, repo, page=1, per_page=20):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/releases"
        url = url_template.format(owner=owner, repo=repo)
        param = "?page={}&per_page={}".format(page, per_page)
        return self.get(url, param)

    def get_pr_list(self, owner, repo, head="", base="", state="all", page=1, per_page=20):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls"
        url = url_template.format(owner=owner, repo=repo)
        param = "?state={}&sort=created&direction=desc&page={}&per_page={}".format(state, page, per_page)
        if head:
            param += "&head={}".format(head)
        if base:
            param += "&base={}".format(base)
        return self.get(url, param)

    def get_pr(self, owner, repo, number):
        """
        Get the info of PR to determine the PR state or existence
        """
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}"
        url = url_template.format(owner=owner, repo=repo, number=number)
        return self.get(url)

    def get_pr_operate_logs(self, owner, repo, number):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/operate_logs"
        url = url_template.format(owner=owner, repo=repo, number=number)
        param = "?sort=desc"
        return self.get(url, param)

    def get_pr_commits(self, owner, repo, number):
        """get all Commit information for a Pull Request. Up to 250 Commit"""
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/commits"
        url = url_template.format(owner=owner, repo=repo, number=number)
        return self.get(url)

    def get_pr_files(self, owner, repo, number):
        """get Pull Request Commit file list. Up to 300 diff"""
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/files"
        url = url_template.format(owner=owner, repo=repo, number=number)
        return self.get(url)

    def get_pr_issues(self, owner, repo, number, page=1, per_page=20):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/issues"
        url = url_template.format(owner=owner, repo=repo, number=number)
        param = "?page={}&per_page={}".format(page, per_page)
        return self.get(url, param)

    def get_pr_comments(self, owner, repo, number, page=1, per_page=20):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/comments"
        url = url_template.format(owner=owner, repo=repo, number=number)
        param = "?page={}&per_page={}".format(page, per_page)
        return self.get(url, param)

    def create_pr_comment(self, owner, repo, number, body):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/comments"
        url = url_template.format(owner=owner, repo=repo, number=number)
        values = {}
        values["body"] = body
        return self.post(url, values)

    def get_pr_labels(self, owner, repo, number, page=1, per_page=20):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/labels"
        url = url_template.format(owner=owner, repo=repo, number=number)
        param = "?page={}&per_page={}".format(page, per_page)
        return self.get(url, param)

    def create_pr_label(self, owner, repo, number, body):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/labels"
        url = url_template.format(owner=owner, repo=repo, number=number)
        values = {}
        values["body"] = body
        return self.post(url, values)

    def replace_pr_label(self, owner, repo, number, body):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/labels"
        url = url_template.format(owner=owner, repo=repo, number=number)
        values = {}
        values["body"] = body
        return self.put(url, values)

    def delete_pr_label(self, owner, repo, number, name):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/labels/{name}"
        url = url_template.format(owner=owner, repo=repo, number=number, name=name)
        return self.delete(url)

    def is_pr_merged(self, owner, repo, number):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/merge"
        url = url_template.format(owner=owner, repo=repo, number=number)
        return self.get(url)

    def merge_pr(self, owner, repo, number, merge_method="merge", prune_source_branch="false"):
        """
        merge_method - merge, squash
        """
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls/{number}/merge"
        url = url_template.format(owner=owner, repo=repo, number=number)
        values = {}
        values["merge_method"] = merge_method
        values["prune_source_branch"] = prune_source_branch
        return self.put(url, values)

    def create_pr(self, owner, repo, title, head, base, body=""):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/pulls"
        url = url_template.format(owner=owner, repo=repo)
        values = {}
        values["title"] = title
        values["head"] = head
        values["base"] = base
        values["body"] = body
        return self.post(url, values)

    def get_issues(self, owner, repo, state="open", page=1, per_page=20):
        """
        state - open, progressing, closed, rejected
        """
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/issues"
        url = url_template.format(owner=owner, repo=repo)
        param = "?state={}&sort=created&direction=desc&page={}&per_page={}".format(state, page, per_page)
        return self.get(url, param)

    def get_one_issue(self, owner, repo, number):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/issues/{number}"
        url = url_template.format(owner=owner, repo=repo, number=number)
        return self.get(url)

    def create_issue(self, owner, repo, title, body=""):
        url_template = "https://gitee.com/api/v5/repos/{owner}/issues"
        url = url_template.format(owner=owner)
        values = {}
        values["repo"] = repo
        values["title"] = title
        values["body"] = body
        return self.post(url, values)

    def update_issue(self, owner, repo, number, state="closed"):
        """
        state - open, progressing, closed
        """
        url_template = "https://gitee.com/api/v5/repos/{owner}/issues/{number}"
        url = url_template.format(owner=owner, number=number)
        values = {}
        values["repo"] = repo
        values["state"] = state
        return self.patch(url, values)

    def get_issue_prs(self, owner, repo, number):
        url_template = "https://gitee.com/api/v5/repos/{owner}/issues/{number}/pull_requests"
        url = url_template.format(owner=owner, number=number)
        param = "?repo={}".format(repo)
        return self.get(url, param)

    def get_issue_operate_logs(self, owner, repo, number):
        url_template = "https://gitee.com/api/v5/repos/{owner}/issues/{number}/operate_logs"
        url = url_template.format(owner=owner, number=number)
        param = "?repo={}&sort=desc".format(repo)
        return self.get(url, param)

    def get_issue_comments(self, owner, repo, number, page=1, per_page=20):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/issues/{number}/comments"
        url = url_template.format(owner=owner, repo=repo, number=number)
        param = "?page={}&per_page={}&order=asc".format(page, per_page)
        return self.get(url, param)

    def create_issue_comment(self, owner, repo, number, body):
        url_template = "https://gitee.com/api/v5/repos/{owner}/{repo}/issues/{number}/comments"
        url = url_template.format(owner=owner, repo=repo, number=number)
        values = {}
        values["body"] = body
        return self.post(url, values)

    def get_licenses(self):
        url = "https://gitee.com/api/v5/licenses"
        return self.get(url)


if __name__ == "__main__":
    pass
